package intermediately

import (
	"github.com/hyperledger/fabric-protos-go/common"
	"github.com/hyperledger/fabric-protos-go/msp"
	"github.com/hyperledger/fabric-protos-go/peer"
	"github.com/hyperledger/fabric-sdk-go/pkg/client/ledger"
	"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/fab"
	"github.com/hyperledger/fabric-sdk-go/pkg/fabsdk"
	"github.com/prometheus/common/log"
)

type Ledger struct {
	context *context
	client  *ledger.Client
}

func NewLedger() *Ledger {
	return &Ledger{
		context: NewContext(),
	}
}

// 1 加载context.json,必须要执行
func (receiver *Ledger) LoadContext(contextJsonPath string) *Ledger {
	receiver.context.SetContextJson(contextJsonPath)
	return receiver
}

// 2 加载config.yaml,必须要执行
func (receiver *Ledger) LoadConfig(configYamlPath string) *Ledger {
	receiver.context.SetConfigYaml(configYamlPath)
	return receiver
}

// 3 start Connect
func (receiver *Ledger) Connect() (*Ledger, error) {
	sdk, err := fabsdk.New(receiver.context.ConfigProvider)
	if err != nil {
		log.Error("! context  ConfigProvider Error !", err.Error())
		return nil, err
	}
	channelClientCtx := sdk.ChannelContext(receiver.context.ChannelID,
		fabsdk.WithUser(receiver.context.UserName),
		fabsdk.WithOrg(receiver.context.Org))
	receiver.client, err = ledger.New(channelClientCtx)
	return receiver, nil
}

func (receiver *Ledger) QueryInfo() (*fab.BlockchainInfoResponse, error) {
	// WithTargetEndpoints 指定查询的peer
	blockInfoResp, err := receiver.client.QueryInfo(ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//jsonRes, errs := json.Marshal(blockInfoResp)
	//if errs != nil {
	//	return "{}", err
	//}
	return blockInfoResp, nil
}

func (receiver *Ledger) QueryBlockByNumber(blockNumber uint64) (*common.Block, error) {
	blockResp, err := receiver.client.QueryBlock(blockNumber, ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//jsonRes, errs := json.Marshal(blockResp)
	//if errs != nil {
	//	log.Error("Json Marshal Error :" + err.Error())
	//	return "{}"
	//}
	return blockResp, nil
}

//	receiver.client.QueryInfo()
//	receiver.client.QueryBlock()
//	receiver.client.QueryBlockByHash()
//	receiver.client.QueryBlockByTxID()
//	receiver.client.QueryConfig()
//	receiver.client.QueryConfigBlock()
//	receiver.client.QueryTransaction()

// 使用json.Marshal后hash会被base64编码，
// 因此在查询的时候需要对字符串型的hash进行解码
// 详情见test
func (receiver *Ledger) QueryBlockByHash(blockHash []byte) (*common.Block, error) {
	blockResp, err := receiver.client.QueryBlockByHash(blockHash, ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//jsonRes, errs := json.Marshal(blockResp)
	//if errs != nil {
	//	return "{}", err
	//}
	return blockResp, nil
}

func (receiver *Ledger) QueryBlockByTxID(txID fab.TransactionID) (*common.Block, error) {
	blockResp, err := receiver.client.QueryBlockByTxID(txID, ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//jsonRes, errs := json.Marshal(blockResp)
	//if errs != nil {
	//	return "{}", err
	//}
	return blockResp, nil
}

type ConfigFunc func(cfg fab.ChannelCfg)

type ChannelConfig struct {
	ID          string               `json:"id"`
	Number      uint64               `json:"number"`
	AnchorPeers []*fab.OrgAnchorPeer `json:"anchor_peers"`
	MSPs        []*msp.MSPConfig     `json:"ms_ps"`
	Orderers    []string             `json:"orderers"`
	Versions    *fab.Versions        `json:"versions"`
}

func (receiver *Ledger) QueryConfig() (*common.Block, error) {

	channnelConfig, err := receiver.client.QueryConfigBlock(ledger.WithTargetEndpoints(receiver.context.Peer))
	//channnelConfig, err := receiver.client.QueryConfig(ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//useConfig(channnelConfig)
	return channnelConfig, nil
}

func (receiver *Ledger) QueryConfigBlock() (*common.Block, error) {
	block, err := receiver.client.QueryConfigBlock(ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//jsonStr, err := json.Marshal(block)
	//if err != nil {
	//	return "{}", err
	//}
	return block, nil
}

func (receiver *Ledger) QueryTransaction(txID fab.TransactionID) (*peer.ProcessedTransaction, error) {
	processedTransaction, err := receiver.client.QueryTransaction(txID, ledger.WithTargetEndpoints(receiver.context.Peer))
	if err != nil {
		return nil, err
	}
	//jsonRes, errs := json.Marshal(processedTransaction)
	//if errs != nil {
	//	return "{}", err
	//}
	return processedTransaction, nil
}
